home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / HyperCard Related / XCMDs & XFCNs / HPopUpMenu 1.1 / HPopUpMenu.p < prev    next >
Encoding:
Text File  |  1991-06-05  |  8.9 KB  |  327 lines  |  [TEXT/MPS ]

  1. {$R-}
  2. {$S HPopUpMenu }
  3.  
  4. { HPopUpMenu( MenuItems, InitialItem, Top, Left )
  5.  
  6.  This HyperCard external function returns the selection from a hierarchical popup
  7.  menu created from a HyperCard item list (the first parameter).  The
  8.  menu is placed on the screen so that the initial item is at the
  9.  position (Top, Left) in global coordinates.
  10.   
  11.  The MenuItems parameter is a number of lines.  The first line is an item list
  12.  of the names of the items in the first-level menu.  Then, each subsequent line
  13.  is a submenu which will be placed under its corresponding first-menu entry.
  14.  For instance:
  15.  
  16.  Foo,Bar,Baz
  17.  Foo Item 1,Foo Item 2,Foo Item 3
  18.  Bar Item 1
  19.  Baz Item 1,Baz Item 2
  20.  
  21.  The return result is a list of two items.  The first item is the number of the
  22.  main menu whose submenu was chosen; the second item is the number of the 
  23.  item from within the submenu.
  24.  
  25.  If the first item of the result is zero, it means that an item was chosen from
  26.  the main menu itself (only possible when that menu had no submenu of its own).
  27.  In this case, the second item of the result is the item number within that menu.
  28.  
  29.  If the second item of the result is zero, then no choice was made at all.
  30.  
  31. }
  32.  
  33. UNIT DummyUnit;
  34.  
  35. INTERFACE
  36.  
  37.     USES MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, HyperXCmd, MenuTools;
  38.  
  39.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  40.  
  41. IMPLEMENTATION
  42.  
  43.     PROCEDURE HPopUpMenu(paramPtr: XCmdPtr);
  44.     FORWARD;
  45.  
  46.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  47.     BEGIN
  48.         HPopUpMenu(paramPtr)
  49.     END { entrypoint } ;
  50.  
  51.  
  52.     PROCEDURE HPopUpMenu(paramPtr: XCmdPtr);
  53.  
  54.     CONST
  55.     FirstMenuID = 128;
  56.     MaxTotalMenus = 50;   {This is arbitrary but FirstMenuID + MaxTotalMenus MUST 
  57.                             be less than 235.  i.e. MaxTotalMenus < 107.}
  58.  
  59.     VAR
  60.     MenuItems:                    Ptr;
  61.     InitialItem:                LONGINT;
  62.     SelectedItem:                LONGINT;
  63.     Top:                        LONGINT;
  64.     Left:                        LONGINT;
  65.     CardWindowTop:                LONGINT;
  66.     CardWindowLeft:                LONGINT;
  67.     FirstLevelSelection:        LONGINT;
  68.     SecondLevelSelection:        LONGINT;
  69.     FirstLevelString:            Str255;
  70.     SecondLevelString:            Str255;
  71.  
  72.         FUNCTION ParamToNum(Param: Handle): LongInt;
  73.  
  74.         VAR
  75.             Str: Str255;
  76.  
  77.         BEGIN
  78.             ZeroToPas(ParamPtr, Param^, Str);
  79.             ParamToNum := StrToNum(ParamPtr, Str);
  80.         END { ParamToNum } ;
  81.  
  82.         FUNCTION NumToParam(Num: LongInt): Handle;
  83.  
  84.         VAR
  85.             Str: Str255;
  86.  
  87.         BEGIN
  88.             NumToStr(ParamPtr, Num, Str);
  89.             NumToParam := PasToZero(ParamPtr, Str)
  90.         END { NumToParam } ;
  91.         
  92.         PROCEDURE ExitWithMessage(aString:    Str255);
  93.         BEGIN
  94.             WITH paramPtr^ DO BEGIN
  95.                 returnValue := PasToZero(ParamPtr, aString);
  96.                 EXIT(HPopUpMenu);
  97.             END;
  98.         END;
  99.  
  100.         PROCEDURE GetCardWindowParams(VAR CardWindowTop: LONGINT; 
  101.                                         VAR CardWindowLeft: LONGINT);
  102.         VAR
  103.             WindowTopString:             Handle;
  104.             WindowLeftString:             Handle;
  105.             AString:                    Str255;
  106.         BEGIN
  107.     
  108.             WindowTopString := EvalExpr(ParamPtr, 'the top of card window');
  109.             WindowLeftString := EvalExpr(ParamPtr, 'the left of card window');
  110.             ZeroToPas(ParamPtr, WindowTopString^, AString);
  111.             CardWindowTop := StrToNum(ParamPtr, AString);
  112.     
  113.             ZeroToPas(ParamPtr, WindowLeftString^, AString);
  114.             CardWindowLeft := StrToNum(ParamPtr, AString);
  115.     
  116.             DisposHandle(WindowTopString);
  117.             DisposHandle(WindowLeftString);
  118.     
  119.         END {GetCardWindowParams} ;
  120.         
  121.         FUNCTION BeginningOfNextLine(CString: Ptr): Ptr;
  122.         VAR
  123.             MatchString:            Str255;
  124.             ReturnCharStart:        Ptr;
  125.         BEGIN
  126.             MatchString[0] := chr(1);     
  127.             MatchString[1] := chr(13);   {MatchString is just a return character.}
  128.         
  129.             ReturnCharStart := StringMatch(ParamPtr, MatchString, CString);
  130.             IF (ReturnCharStart = NIL) THEN 
  131.             BEGIN
  132.                 BeginningOfNextLine := NIL;
  133.                 Exit(BeginningOfNextLine)
  134.             END;
  135.             
  136.             {Skip the found return character.}
  137.             BeginningOfNextLine := Ptr(Ord4(ReturnCharStart) + 1);             
  138.         END;
  139.         
  140.         {Returns the number of lines in a CString.}
  141.         FUNCTION NumberOfLinesInPtr(CString: Ptr): LONGINT;
  142.         VAR
  143.             NumLines:    LONGINT;
  144.         BEGIN        
  145.             NumLines := 1;
  146.             NumberOfLinesInPtr := NumLines;
  147.  
  148.             WHILE true DO
  149.             BEGIN
  150.                 CString := BeginningOfNextLine(CString);
  151.                 IF (CString = NIL) THEN Exit(NumberOfLinesInPtr);
  152.                 NumLines := NumLines + 1;
  153.                 NumberOfLinesInPtr := NumLines
  154.             END
  155.         END;
  156.         
  157.         FUNCTION Min(Val1, Val2: INTEGER): INTEGER;
  158.         BEGIN
  159.             IF (Val1 < Val2) THEN Min := Val1 ELSE Min := Val2;
  160.         END;
  161.     
  162.         PROCEDURE AppendFirstLineMenuItemsPtr(Menu: MenuHandle; MenuItems: Ptr);
  163.     
  164.         VAR
  165.             StartPos:                LONGINT;
  166.             EndHasBeenReached:        Boolean;
  167.             LengthOfLine:            INTEGER;
  168.             NewLength:                INTEGER;
  169.             PasMenuItems:            Str255;
  170.             NextLinePtr:            Ptr;
  171.         BEGIN
  172.             
  173.             { The input is a Ptr string (C-style string) containing possibly 
  174.               more than 250 characters of menu items to be added to the list.
  175.               We break the input up into 250 character chunks as many times as possible,
  176.               calling AppendAllMenuItems on each chunk. Items past the first return
  177.               character will be ignored.}
  178.               
  179.             StartPos := 0;
  180.             EndHasBeenReached := false;
  181.             
  182.             REPEAT
  183.             
  184.                 ZeroToPas(ParamPtr, Pointer(Ord4(MenuItems) + StartPos), PasMenuItems);
  185.                 NewLength := length(PasMenuItems);
  186.  
  187.                 NextLinePtr := BeginningOfNextLine(Pointer(Ord4(MenuItems) + StartPos));
  188.  
  189.                 IF (NextLinePtr <> NIL) THEN
  190.                     BEGIN
  191.                         LengthOfLine := Ord4(NextLinePtr) - (Ord4(MenuItems) + StartPos) - 1;
  192.                         NewLength := Min(NewLength,LengthOfLine)
  193.                     END;
  194.  
  195.                 
  196.                 IF (NewLength > 250) THEN
  197.                     BEGIN
  198.                         FOR NewLength := 250 DOWNTO 1 DO
  199.                             IF (PasMenuItems[NewLength] = ',') THEN Leave;
  200.                         NewLength := NewLength - 1;
  201.                     END
  202.                 ELSE
  203.                     EndHasBeenReached := true;
  204.                     
  205.                 IF (NewLength) <= 0 THEN Exit(AppendFirstLineMenuItemsPtr);
  206.                 PasMenuItems[0] := chr(NewLength);
  207.                 AppendAllMenuItems(Menu, PasMenuItems);
  208.                 StartPos := StartPos + NewLength + 1
  209.                         
  210.             UNTIL (EndHasBeenReached = true);
  211.         
  212.         END { AppendFirstLineMenuItemsPtr } ;
  213.     
  214.         PROCEDURE DoHPopUpMenuPtr(FirstMenuID: INTEGER; MenuItems: Ptr; InitialItem: LONGINT;
  215.                             Top: LONGINT; Left: LONGINT;
  216.                             VAR FirstLevelSelection: LONGINT; 
  217.                             VAR SecondLevelSelection: LONGINT);
  218.         VAR
  219.         Menu:                    MenuHandle;
  220.         TheMenus:                PACKED ARRAY [1..MaxTotalMenus] of MenuHandle;
  221.         TotalNumberOfMenus:        INTEGER;
  222.         MenuIndex:                INTEGER;
  223.         NextItemsLine:            Ptr;
  224.         PopupResult:            LONGINT;
  225.         SelectedMenuID:            INTEGER;    
  226.         ItemSelected:            INTEGER;    
  227.     
  228.         BEGIN
  229.         
  230.             { Count the number of menus necessary.  Limit it to MaxTotalMenus.}
  231.             TotalNumberOfMenus := NumberOfLinesInPtr(MenuItems);
  232.             IF TotalNumberOfMenus > MaxTotalMenus THEN TotalNumberOfMenus := MaxTotalMenus;
  233.             
  234.             { Call NewMenu to make all of the required menus.}
  235.             
  236.             FOR MenuIndex := 1 to TotalNumberOfMenus DO 
  237.                 TheMenus[MenuIndex] := NewMenu(FirstMenuID + MenuIndex - 1,'');
  238.             
  239.             { Append the items in the appropriate line to their corresponding menu.}
  240.             
  241.             NextItemsLine := MenuItems;
  242.             FOR MenuIndex := 1 to TotalNumberOfMenus DO 
  243.             BEGIN
  244.                 AppendFirstLineMenuItemsPtr(TheMenus[MenuIndex], NextItemsLine);
  245.                 NextItemsLine := BeginningOfNextLine(NextItemsLine);
  246.                 IF StringLength(ParamPtr, NextItemsLine) < 1 THEN Leave;
  247.             END;
  248.  
  249.             { Attach each submenu with 1 or more item to its spot in the top menu. }
  250.             
  251.             FOR MenuIndex := 2 to TotalNumberOfMenus DO 
  252.             BEGIN
  253.                 IF (CountMItems(TheMenus[MenuIndex]) > 0) THEN
  254.                 BEGIN
  255.                     SetItemCmd(TheMenus[1], MenuIndex - 1, char($1B));
  256.                     SetItemMark(TheMenus[1], MenuIndex - 1, char(FirstMenuID + MenuIndex - 1))
  257.                 END
  258.             END;
  259.  
  260.             { Insert all of the menus into the menus list. }
  261.             FOR MenuIndex := 1 to TotalNumberOfMenus DO 
  262.                 InsertMenu(TheMenus[MenuIndex], -1);
  263.     
  264.             { Do the popup }
  265.             PopUpResult := PopUpMenuSelect(TheMenus[1], Top, Left, InitialItem);
  266.             SelectedMenuID := HiWord(PopUpResult);
  267.             ItemSelected := LoWord(PopUpResult);
  268.             
  269.             IF (SelectedMenuID <> 0) THEN
  270.                 BEGIN
  271.                     FirstLevelSelection := SelectedMenuID - FirstMenuID;
  272.                     SecondLevelSelection := ItemSelected
  273.                 END
  274.             ELSE
  275.                 BEGIN
  276.                     FirstLevelSelection := ItemSelected;
  277.                     SecondLevelSelection := 0
  278.                 END;
  279.  
  280.             { Delete the menus from the menu list.}
  281.             FOR MenuIndex := 1 to TotalNumberOfMenus DO 
  282.                 DeleteMenu(FirstMenuID + MenuIndex - 1);
  283.             
  284.             { Dispose of the menu and all submenus. }
  285.             FOR MenuIndex := 1 to TotalNumberOfMenus DO 
  286.                 DisposeMenu(TheMenus[MenuIndex])
  287.     
  288.         END; {DoHPopUpMenuPtr}
  289.     
  290.     BEGIN {HPopUpMenu}
  291.  
  292.         WITH paramPtr^ DO
  293.         BEGIN
  294.  
  295.             { Parse parameters & Get Menu Position }
  296.             MenuItems := Params[1]^;
  297.             InitialItem := ParamToNum(Params[2]);
  298.             GetCardWindowParams(CardWindowTop, CardWindowLeft);
  299.             Top := CardWindowTop + ParamToNum(Params[3]);
  300.             Left := CardWindowLeft + ParamToNum(Params[4]);
  301.             
  302.             IF (StringLength(ParamPtr, MenuItems) <> 0) THEN
  303.  
  304.                 { Run the popup menu }
  305.                 DoHPopUpMenuPtr(FirstMenuID, MenuItems, InitialItem, Top, Left,
  306.                                 FirstLevelSelection, SecondLevelSelection)
  307.             ELSE
  308.                 BEGIN
  309.                     FirstLevelSelection := 0;
  310.                     SecondLevelSelection := 0
  311.                 END;
  312.                 
  313.             NumToStr(ParamPtr, FirstLevelSelection, FirstLevelString);
  314.             NumToStr(ParamPtr, SecondLevelSelection, SecondLevelString);
  315.  
  316.             { Return the selection }
  317.             ExitWithMessage(concat(FirstLevelString, ',', SecondLevelString))
  318.  
  319.         END
  320.  
  321.     END { HPopUpMenu } ;
  322.  
  323. END. { DummyUnit }
  324.  
  325.  
  326.  
  327.